syslib.comet = {
	AUTOMATIC : 'automatic', 
	LONGPOOLING : 'long-pooling',
	HTMLFILE : 'htmlfile',
	MULTIPART : 'multipart',
	EVENTSOURCE : 'event-source',

	_defaultOptions : {
		name : 'syslib-comet', 
		type : 'automatic', 
		callback : function(){}, 
		parameters : {}, 
		onOpen : null
	}, 

	request : function(url, options){
		// format the options
		options = syslib.object.extend(this._defaultsOptions, options);

		// get the type
		var type = options.type;

		// check the type
		if(!__valid(type) || type == this.AUTOMATIC){
			// find the best type
			if(syslib.util.isOpera()){
				type = this.EVENTSOURCE;
			} else if(syslib.util.isFirefox()){
				type = this.MULTIPART;
			} else if(syslib.util.isIE()){
				type = this.HTMLFILE;
			} else {
				type = this.LONGPOOLING;
			}
		}
		
		// log
		syslib.messages.info("syslib.comet.request(): Request type: " + type);
		
		if(type == this.LONGPOOLING){
			// create a long-pooling transport (supported my bost browsers)
			transport = new syslib.comet.LongPoolingTransport(url, type, options);
		} else if(type == this.MULTIPART) {
			// create a multipart transport (only Firefox)
			transport = new syslib.comet.MultiPartTransport(url, type, options);
		} else if(type == this.HTMLFILE) {
			// create a multipart transport (only IE)
			transport = new syslib.comet.HTMLFileTransport(url, type, options);
		} else if(type == this.EVENTSOURCE) {
			// create a multipart transport (only HTML5 browsers)
			transport = new syslib.comet.EventSourceTransport(url, type, options);
		} else {
			// invalid transport type
			syslib.messages.error("sysllib.comet.request(): Invalid transport type!");
		}

		// open
		transport.open();

		// return 
		return transport;
	}, 

	Transport : {
		_defaultOptions : {
			name : "syslib-comet", 
			parameters : {}, 
			callback : null
		}, 
		
		_url : null, 
		_options : null,
		
		__construct : function(url, type, options){
			// format the url
			this._url = url + (url.indexOf("?") == -1 ? "?" : "&") + "ce=true&ct=" + type;
			
			// set the options
			this._options = syslib.object.extend(this._defaultOptions, options);
		}, 

		open : function(){
			throw 'Abstract method';
		},

		send : function(){
			throw 'Abstract method';
		},

		cancel : function(){
			throw 'Abstract method';
		},

		setCallback : function(callback){
			if(typeof callback === 'function'){
				this._options.callback = callback;
			}
			
		}, 

		setParameter : function(name, value){
			this._options.parameters[name] = value;
		},
		
		onComplete : function(){
			throw "Abstract method";
		}, 

		onOpen : function(){
			if(__valid(this._options.onOpen) && typeof this._options.onOpen === 'function'){
				this._options.onOpen(this);
			}
		}
	}
};

syslib.comet.Response = __class({
	eventName : null, 
	data : null, 
	aditionalParameters : null,

	__construct : function(eventName, data, aditionalParameters){
		this.eventName = eventName;
		this.data = data;
		if(__valid(aditionalParameters)){
			this.aditionalParameters = aditionalParameters;
		}
	}
});

syslib.comet.LongPoolingTransport = __class(syslib.comet.Transport, {
	_tunnel : null, 
	_headers : null, 

	open : function(){
		// call the onopen event
		this.onOpen();
	
		// prepare the headers
		this._headers = {"Connection" : "Keep-Alive"};

		// create the request
		this._tunnel = new syslib.ajax.request(this._url, {
			method : "GET",
			autoSend : false, 
			parameters : syslib.object.serialize(this._options.parameters),
			onSuccess : this.onComplete.applyTo(this)
		}, this._headers, false);

		// set the event to clear the garbage
		syslib.event.listen("unload", document.body, function(){
			// cancel
			this.cancel();
		}.applyTo(this));
	},

	send : function(){
		// send the request
		this._tunnel.prepareAndSend();
	}, 

	cancel : function(){
		// abort the request
		this._tunnel.request.abort();
		this._tunnel = null;
	}, 

	onComplete : function(transport){
		// create the response
		response = new syslib.comet.Response('long-pooling event', transport.responseText);

		// callback
		this._options.callback(response);

		// cancel
		this.cancel();

		// reopen and send
		this.open();
		this.send();
	}
});


syslib.comet.HTMLFileTransport = __class(syslib.comet.Transport, {
	_tunnel : null, 

	open : function(){
		// call the onopen event
		this.onOpen();

		// craete the ActiveX object
		this._tunnel = new ActiveXObject("htmlfile");

		// open
		this._tunnel.open();

		// set the domain
		this._tunnel.write("<html><body></body></html>");

		// close
		this._tunnel.close();

		// set the comet object
		this._tunnel.parentWindow._comet = this;

		// set the event to clear the garbage
		syslib.event.listen("unload", document.body, function(){
			// cancel
			this.cancel();
		}.applyTo(this));
	},

	send : function(){
		// format the url
		this._url = this._url + syslib.object.serialize(this._options.parameters);

		// create the iframe
		this._tunnel.body.innerHTML = "<iframe src='" + this._url  + "'></iframe>";
	}, 

	cancel : function(){
		// clear the tunnel
		this._tunnel.body.innerHTML = "<iframe src='about:blank'></iframe>";

		// delete the tunnel
		this._tunnel = null;

		// call the garbage collector
		CollectGarbage();
	}, 

	onComplete : function(data){
		// create the response
		response = new syslib.comet.Response('htmlfile event', data);

		// callback
		this._options.callback(response);
	}
});

syslib.comet.MultiPartTransport = __class(syslib.comet.Transport, {
	_tunnel : null, 
	_headers : null, 

	open : function(){
		// call the onopen event
		this.onOpen();
		
		// prepare the headers
		this._headers = {"Connection" : "Keep-Alive"};

		// create the request
		this._tunnel = new syslib.ajax.request(this._url, {
			method : "GET",
			autoSend : false,  
			parameters : syslib.object.serialize(this._options.parameters),
			onSuccess : this.onComplete.applyTo(this)
		}, this._headers, false);

		// set as multipart
		this._tunnel.request.multipart = true;

		// set the event to clear the garbage
		syslib.event.listen("unload", document.body, function(){
			// cancel
			this.cancel();
		}.applyTo(this));
	},

	send : function(){
		// send the request
		this._tunnel.prepareAndSend();
	}, 

	cancel : function(){
		// abort the request
		this._tunnel.request.abort();
		this._tunnel = null;
	}, 

	onComplete : function(transport){
		// create the response
		response = new syslib.comet.Response('multipart event', transport.responseText);

		// callback
		this._options.callback(response);
	}
}); 

syslib.comet.EventSourceTransport = __class(syslib.comet.Transport, {
	open : function(){
		// call the onopen event
		this.onOpen();
		
		// create the event-source
		this._tunnel = document.createElement("event-source");

		// set the event to clear the garbage
		syslib.event.listen("unload", document.body, function(){
			// cancel
			this.cancel();
		}.applyTo(this));
	},

	send : function(){
		// set the source
		this._tunnel.setAttribute("src", this._url);
		
		// set the event listener
		syslib.event.listen(this._options.name, this._tunnel, this.onComplete.applyTo(this));
	}, 

	cancel : function(){
		// cancel
		if(__valid(this._tunnel.parentNode)){
			this._tunnel.parentNode.removeChild(this._tunnel);
		}		
		this._tunnel = null;
	}, 

	onComplete : function(transport){
		// create the response
		var response = new syslib.comet.Response('event-source event', transport.data);

		// callback
		this._options.callback(response);
	}
});
